#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
#include <string>
#include <algorithm>
#include <sstream>

using namespace std;

const int INF = 0x3f3f3f3f;

struct Edge {
    int to, weight;
};

int main() {
    int numNodes;
    cin >> numNodes;

    vector<char> nodes(numNodes);
    for (int i = 0; i < numNodes; ++i) {
        cin >> nodes[i];
    }

    // 构建邻接表
    unordered_map<char, vector<Edge>> graph;
    vector<int> inDegree(numNodes, 0);
    string line;
    bool hasEdges = false;
    getline(cin, line); // 吸收换行符
    while (getline(cin, line)) {
        if (line.empty()) break; // 遇到空行停止读取
        istringstream iss(line);
        char u, v;
        int weight;
        if (!(iss >> u >> v >> weight)) {
            cerr << "输入格式错误" << endl;
            return 1;
        }
        graph[u].push_back({v, weight});
        inDegree[v - 'A']++;
        hasEdges = true;
    }

    if (!hasEdges) {
        cerr << "没有提供边信息" << endl;
        return 1;
    }

    // 拓扑排序
    queue<char> q;
    for (char node : nodes) {
        if (inDegree[node - 'A'] == 0) {
            q.push(node);
        }
    }

    vector<int> earliestStart(numNodes, 0);
    vector<int> latestStart(numNodes, INF);

    while (!q.empty()) {
        char node = q.front();
        q.pop();

        for (const auto& edge : graph[node]) {
            char nextNode = edge.to;
            int weight = edge.weight;

            inDegree[nextNode - 'A']--;
            if (inDegree[nextNode - 'A'] == 0) {
                q.push(nextNode);
            }

            earliestStart[nextNode - 'A'] = max(earliestStart[nextNode - 'A'], earliestStart[node - 'A'] + weight);
        }
    }

    // 检查是否有环
    if (count(inDegree.begin(), inDegree.end(), 0) != numNodes) {
        cerr << "图中存在环，无法进行拓扑排序" << endl;
        return 1;
    }

    // 计算最晚开始时间
    latestStart[nodes.back() - 'A'] = earliestStart[nodes.back() - 'A'];
    for (int i = nodes.size() - 1; i >= 0; --i) {
        char node = nodes[i];
        for (const auto& edge : graph[node]) {
            char nextNode = edge.to;
            int weight = edge.weight;

            latestStart[node - 'A'] = min(latestStart[node - 'A'], latestStart[nextNode - 'A'] - weight);
        }
    }

    // 计算关键路径
    int criticalPathLength = 0;
    for (int i = 0; i < nodes.size(); ++i) {
        char node = nodes[i];
        for (const auto& edge : graph[node]) {
            char nextNode = edge.to;
            int weight = edge.weight;

            if (earliestStart[node - 'A'] + weight == earliestStart[nextNode - 'A'] && 
                latestStart[nextNode - 'A'] - weight == latestStart[node - 'A']) {
                criticalPathLength += weight;
            }
        }
    }

    cout << "Critical path length: " << criticalPathLength << endl;

    return 0;
}